Attribute VB_Name = "modOcxLoader"
'***************************************************************
' (c) Copyright 2000 Matthew J. Curland
'
' This file is from the CD-ROM accompanying the book:
' Advanced Visual Basic 6: Power Techniques for Everyday Programs
'   Author: Matthew Curland
'   Published by: Addison-Wesley, July 2000
'   ISBN: 0-201-70712-8
'   http://www.PowerVB.com
'
' You are entitled to license free distribution of any application
'   that uses this file if you own a copy of the book, or if you
'   have obtained the file from a source approved by the author. You
'   may redistribute this file only with express written permission
'   of the author.
'
' This file depends on:
'   References:
'     VBoostTypes6.olb (VBoost Object Types (6.0))
'     ObjCreate.olb (VBoost: Object Creation and Security) 
'     VBoost6.Dll (VBoost Object Implementation (6.0)) (optional)
'   Files:
'     FunctionDelegator.bas
'     COMDllLoader.bas
'     VBoost.bas
'   Minimal VBoost conditionals:
'     VBOOST_INTERNAL = 1 : VBOOST_CUSTOM = 1 : VBOOST_AggregateUnknown = 1
'   Conditional Compilation Values:
'     FUNCTIONDELEGATOR_NOHEAP = 1 'Minimize FunctionDelegator impact
'
' This file is discussed in Chapter 7.
'***************************************************************
Option Explicit

Public Type OcxLoadData
    hInstDLL As Long
    Hook As UnknownHook
End Type

Public Type OcxTargetData
    TargetOcx As String
    CLSID As CLSID
    RTLicenseKey As String
    fTargetAbsolute As Boolean
End Type
Public g_OcxTargetData As OcxTargetData

Private Type OcxHookAggData
    AggData(1) As AggregateData
    pIIDs(0) As IID
End Type

'Load an Ocx based on a relative path into the Wrapper object.
'This should be called from the UserControl_Initialize event
'of the wrapper UserControl class.
'
'TargetOcx:       Path to the Ocx relative to the application,
'                 unless fTargetAbsolute is true, in which case
'                 this is an absolute path.
'CLSID_Target:    CLSID supported by the wrapped Ocx
'RTLicenseKey:    The key to create a control that doesn't have
'                 a registered license key. Can be obtained from
'                 IClassFactory2.RequestLicKey using the
'                 GetRTLicKey utility on a machine where the
'                 control is fully licensed.
'fTargetAbsolute: An optional flag indicate that the TargetOcx
'                 argument is an absolute, not a relative, path
Public Sub LoadWrappedOcx(LoadData As OcxLoadData, ByVal Wrapper As IUnknown, TargetOcx As String, CLSID_Target As CLSID, Optional RTLicenseKey As String, Optional ByVal fTargetAbsolute As Boolean = False)
Dim HookData As OcxHookAggData
Dim pCF As IClassFactory
Dim pCF2 As IClassFactory2
    
    'If this is used at design time, then Sub Main may
    'not have run, so the VBoost object has not been
    'created.
    If VBoost Is Nothing Then InitVBoost
    
    'Use the helper function to load the Ocx
    If fTargetAbsolute Then
        Set pCF = GetDllClassObject(TargetOcx, CLSID_Target, LoadData.hInstDLL)
    Else
        Set pCF = GetDllClassObject(App.Path & "\" & TargetOcx, CLSID_Target, LoadData.hInstDLL)
    End If
    
    'See about licensing
    If Len(RTLicenseKey) Then
        Set pCF2 = pCF
        With pCF2.GetLicInfo
            If .fLicVerified Then
                'pCF.CreateInstance will succeed
                Set pCF2 = Nothing
            Else
                If 0 = .fRuntimeKeyAvail Then
                    'Can only load a licensed control
                    TestUnloadDll LoadData.hInstDLL
                    Exit Sub
                End If
            End If
        End With
    End If
    
    'Aggregate the created object with priority before the
    'wrapping object. The adNoDelegator removes the
    'per-interface overhead of the aggregator, but breaks COM
    'identity with the wrapping object. In practice, we don't
    'really care much about the wrapping object, and there are
    'a substantial amount of interfaces that need to be wrapped
    'with a custom control, so we use adNoDelegator.
    With HookData.AggData(0)
        .Flags = adIgnoreIIDs Or adBeforeHookedUnknown Or adNoDelegator
        If pCF2 Is Nothing Then
            Set .pObject = pCF.CreateInstance(Nothing, IID_IUnknown)
        Else
            Set .pObject = pCF2.CreateInstanceLic(Nothing, Nothing, IID_IUnknown, RTLicenseKey)
        End If
    End With
    
    'Block IQuickActivate
    With HookData.AggData(1)
        HookData.pIIDs(0) = IIDFromString(strIID_IQuickActivate)
        .FirstIID = 0
        .Flags = adBlockIIDs
    End With
        
    VBoost.AggregateUnknown _
      Wrapper, HookData.AggData, HookData.pIIDs, LoadData.Hook
End Sub

'Call LoadWrappedOcx using the global data
Public Sub LoadWrappedOcxFromGlobalTargetData(LoadData As OcxLoadData, ByVal Wrapper As IUnknown)
    With g_OcxTargetData
        LoadWrappedOcx LoadData, Wrapper, .TargetOcx, .CLSID, .RTLicenseKey, .fTargetAbsolute
    End With
End Sub

'Unload the OCX file. This should be called from the
'UserControl_Terminate event of the wrapper control.
Public Sub UnloadWrappedOCX(LoadData As OcxLoadData)
    'Unhook to release all references on the wrapped object
    Set LoadData.Hook = Nothing
    'Let go of the Ocx file if no one else is using it.
    TestUnloadDll LoadData.hInstDLL
End Sub

